using System;
using System.Collections.Generic;

using lucere.io;
using lucere.entity;

namespace lucere.index
{
    /// <summary>
    /// Access to the Fieldable Info file that describes document fields and whether or 
    /// not they are indexed. Each segment has a separate Fieldable Info file. Objects
    /// of this class are thread-safe for multiple readers, but only one thread can
    /// be adding documents at a time, with no other reader or writer threads
    /// accessing this object.
    /// </summary>
    public interface IFieldInfos : ICloneable
    {
        /// <summary>
        /// Adds field info for a Document.
        /// </summary>
        /// <param name="doc"></param>
        void Add(IDocument doc);

        /// <summary>
        /// Returns true if any fields do not omitTermFreqAndPositions
        /// </summary>
        bool HasProximityData { get; } 

        /// <summary>
        /// Add fields that are indexed. Whether they have termvectors has to be specified.
        /// </summary>
        /// <param name="names">The names of the fields</param>
        /// <param name="storeTermVectors">Whether the fields store term vectors or not</param>
        /// <param name="storePositionWithTermVector">true if positions should be stored.</param>
        /// <param name="storeOffsetWithTermVector">true if offsets should be stored</param>
        void AddIndexed(ICollection<string> names, bool storeTermVectors, bool storePositionWithTermVector, bool storeOffsetWithTermVector);


        /// <summary>
        /// Assumes the fields are not storing term vectors.
        /// </summary>
        /// <param name="names">The names of the fields</param>
        /// <param name="isIndexed"></param>
        void Add(ICollection<string> names, bool isIndexed);

        /// <summary>
        /// Calls 5 parameter add with false for all TermVector parameters.
        /// </summary>
        /// <param name="name">The name of the Fieldable</param>
        /// <param name="isIndexed">true if the field is indexed</param>
        void Add(string name, bool isIndexed);

        /// <summary>
        /// Calls 5 parameter add with false for term vector positions and offsets.
        /// </summary>
        /// <param name="name">The name of the field</param>
        /// <param name="isIndexed">true if the field is indexed</param>
        /// <param name="storeTermVector"> true if the term vector should be stored</param>
        void Add(string name, bool isIndexed, bool storeTermVector);
 
        /// <summary>
        /// If the field is not yet known, adds it. If it is known, checks to make sure that the 
        /// isIndexed flag is the same as was given previously for this field. If not - marks it 
        /// as being indexed.  Same goes for the TermVector parameters.
        /// </summary>
        /// <param name="name">The name of the field</param>
        /// <param name="isIndexed">true if the field is indexed</param>
        /// <param name="storeTermVector">true if the term vector should be stored</param>
        /// <param name="storePositionWithTermVector">true if the term vector with positions should be stored</param>
        /// <param name="storeOffsetWithTermVector">true if the term vector with offsets should be stored</param>
        void Add(string name, bool isIndexed, bool storeTermVector, bool storePositionWithTermVector, bool storeOffsetWithTermVector);

        /// <summary>
        /// If the field is not yet known, adds it. If it is known, checks to make sure that the isIndexed flag is the same as was given previously for this field. If not - marks it as being indexed.  Same goes for the TermVector parameters.
        /// </summary>
        /// <param name="name">The name of the field</param>
        /// <param name="isIndexed">true if the field is indexed</param>
        /// <param name="storeTermVector">true if the term vector should be stored</param>
        /// <param name="storePositionWithTermVector">true if the term vector with positions should be stored</param>
        /// <param name="storeOffsetWithTermVector">true if the term vector with offsets should be stored</param>
        /// <param name="omitNorms">true if the norms for the indexed field should be omitted</param>
        void Add(string name, bool isIndexed, bool storeTermVector, bool storePositionWithTermVector, bool storeOffsetWithTermVector, bool omitNorms);


        /// <summary>
        /// If the field is not yet known, adds it. If it is known, checks to make sure that the isIndexed flag 
        /// is the same as was given previously for this field. If not - marks it as being indexed.  Same goes 
        /// for the TermVector parameters.
        /// </summary>
        /// <param name="name">The name of the field</param>
        /// <param name="isIndexed">true if the field is indexed</param>
        /// <param name="storeTermVector">true if the term vector should be stored</param>
        /// <param name="storePositionWithTermVector">true if the term vector with positions should be stored</param>
        /// <param name="storeOffsetWithTermVector">true if the term vector with offsets should be stored</param>
        /// <param name="omitNorms">true if the norms for the indexed field should be omitted</param>
        /// <param name="storePayloads">true if payloads should be stored for this field</param>
        /// <param name="omitTermFreqAndPositions">true if term freqs should be omitted for this field</param>
        /// <returns></returns>
        IFieldInfo Add(string name, bool isIndexed, bool storeTermVector, bool storePositionWithTermVector, bool storeOffsetWithTermVector,
                       bool omitNorms, bool storePayloads, bool omitTermFreqAndPositions);

        int GetFieldNumber(string fieldName);

        IFieldInfo GetFieldInfo(string fieldName);

        /// <summary>
        /// Return the fieldName identified by its number.
        /// </summary>
        /// <param name="fieldNumber"></param>
        /// <returns>the fieldName or an empty string when the field with the given number doesn't exist.</returns>
        string GetFieldName(int fieldNumber);

        /// <summary>
        /// Return the fieldinfo object referenced by the fieldNumber.
        /// </summary>
        /// <param name="fieldNumber"></param>
        /// <returns>the FieldInfo object or null when the given fieldNumber doesn't exist.</returns>
        IFieldInfo GetFieldInfo(int fieldNumber);

        int Size { get; }

        bool HasVectors { get; }

        void Write(IDirectory directory, string name);
        void Write(IIndexOutput output);
        void Read(IIndexInput input, string fileName);
    }
}